﻿using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using UnityEngine;

namespace FutureCore
{
    public class TimerInfo
    {
        public int repeatCount;
        public float interval;
        public Action<TimerInfo> onCallBack;
        public object[] args;
        public float time;

        public TimerInfo(float interval, Action<TimerInfo> onCallBack, params object[] args)
        {
            repeatCount = 1;
            this.interval = interval;
            this.onCallBack = onCallBack;
            this.args = args;
            time = Timer.GetTriggerTime(interval);
        }

        public TimerInfo(int repeatCount, float interval, Action<TimerInfo> onCallBack, params object[] args)
        {
            this.repeatCount = repeatCount;
            this.interval = interval;
            this.onCallBack = onCallBack;
            this.args = args;
            time = Timer.GetTriggerTime(interval);
        }
    }

    public class Timer : MonoBehaviour
    {
        public const int INFINITE_LOOP = -1;

        private List<TimerInfo> timerInfoList = new List<TimerInfo>();
        private List<TimerInfo> triggers = new List<TimerInfo>();

        private void Update()
        {
            if (timerInfoList.Count > 0)
            {
                triggers.Clear();
                foreach (TimerInfo timerInfo in timerInfoList)
                {
                    if (timerInfo.time <= Time.time)
                    {
                        triggers.Add(timerInfo);
                    }
                }
                for (int i = 0; i < triggers.Count; i++)
                {
                    TimerInfo timerInfo = triggers[i];
                    if (timerInfo.repeatCount != INFINITE_LOOP)
                    {
                        timerInfo.repeatCount--;
                    }
                    if (timerInfo.repeatCount == 0)
                    {
                        timerInfoList.Remove(timerInfo);
                    }
                    else
                    {
                        timerInfo.time = GetTriggerTime(timerInfo.interval);
                    }

                    timerInfo.onCallBack(timerInfo);
                }
            }
        }

        public TimerInfo AddTimer(float interval, Action<TimerInfo> onCallBack, params object[] args)
        {
            TimerInfo timeInfo = new TimerInfo(interval, onCallBack, args);
            AddTimer(timeInfo);
            return timeInfo;
        }

        public TimerInfo AddRepeatTimer(int repeatCount, float interval, Action<TimerInfo> onCallBack, params object[] args)
        {
            TimerInfo timeInfo = new TimerInfo(repeatCount, interval, onCallBack, args);
            AddTimer(timeInfo);
            return timeInfo;
        }

        public void AddTimer(TimerInfo timerInfo)
        {
            if (null != timerInfo)
            {
                if (timerInfo.interval <= 0)
                {
                    timerInfo.onCallBack(timerInfo);
                    return;
                }
                timerInfoList.Add(timerInfo);
            }
        }

        public void RemoveTimer(TimerInfo timerInfo)
        {
            if (null != timerInfo)
            {
                if (timerInfoList.Contains(timerInfo))
                {
                    timerInfoList.Remove(timerInfo);
                }
            }
        }

        public void ClearAll()
        {
            timerInfoList.Clear();
            triggers.Clear();
        }

        public void Destroy()
        {
            Destroy(this);
        }

        public static float GetTriggerTime(float interval)
        {
            return Time.time + interval;
        }

        void OnDestroy()
        {
            ClearAll();
            timerInfoList = null;
            triggers = null;
        }
    }
}